package com.secsbrain.deploy.web.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.secsbrain.cmdb.client.iface.AppInfoService;
import com.secsbrain.deploy.biz.utils.HttpResponse;
import com.secsbrain.deploy.biz.utils.JenkinsHttpUtils;
import com.secsbrain.deploy.biz.IBuildModelService;
import com.secsbrain.deploy.biz.IBuildRecordService;
import com.secsbrain.deploy.biz.IBuildTemplateService;
import com.secsbrain.deploy.client.constant.EnumDefinition;
import com.secsbrain.deploy.client.iface.DeployService;
import com.secsbrain.deploy.dal.model.BuildModel;
import com.secsbrain.deploy.dal.model.BuildRecord;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.plugins.Page;
import com.secsbrain.cmdb.client.model.AppDetail;
import com.secsbrain.cmdb.client.model.Server;
import com.secsbrain.cmdb.client.model.SystemTypeEnums;
import com.secsbrain.common.ErrorCodeEnum;
import com.secsbrain.common.ResponseVo;
import com.secsbrain.deploy.client.model.BatchBuildParam;
import com.secsbrain.deploy.client.model.BatchBuildResult;
import com.secsbrain.deploy.client.model.BuildLog;
import com.secsbrain.deploy.client.model.BuildParam;
import com.secsbrain.deploy.client.model.HealthDto;
import com.secsbrain.deploy.client.model.JobNameBuildParam;

/**
 * 构建相关控制层
 * @author zhaoyi
 *
 */
@RestController
public class DeployServiceImpl implements DeployService {
	
    private static final Logger logger = LoggerFactory.getLogger(DeployServiceImpl.class);

    @Autowired
	AppInfoService appInfoService;
    
    @Autowired
    IBuildTemplateService buildTemplateService;
    
    @Autowired
    IBuildModelService buildModelService;
    
    @Autowired
    IBuildRecordService buildRecordService;
	
    @Value("${jenkins.url}")
	private String jenkinsUrl;
	
	@Value("${jenkins.userid}")
	private String userid;
	
	@Value("${jenkins.token}")
	private String token;
	
	@Value("${jenkins.k8s.url}")
	private String jenkinsK8sUrl;
	
	@Value("${jenkins.k8s.userid}")
	private String useridK8s;
	
	@Value("${jenkins.k8s.token}")
	private String tokenK8s;
	
	/**
	 * 功能描述: <br>
	 * 校验并获取应用信息
	 *
	 * @param buildParam
	 * @return
	 */
	private AppDetail valicateApp(BuildParam buildParam){
		BuildModel buildModelParam=new BuildModel();
        buildModelParam.setAppId(buildParam.getAppId());
		buildModelParam.setEnv(buildParam.getEnvName());
        int count=buildModelService.selectCount(buildModelParam);
		Assert.isTrue(count>0, "应用构建模型不存在");
		
		ResponseVo<AppDetail> responseVo=appInfoService.queryAppDetailById(buildParam.getAppId());
		Assert.isTrue(responseVo.isSuccess(), responseVo.getMsg());
        
		AppDetail app=responseVo.getData();
        List<Server> newList=new ArrayList<>();
        List<Server> serverList=app.getServerList();
        logger.debug("serverList:{}",serverList);
        for(Server server:serverList){
        	if(buildParam.getEnvName()!=null&&buildParam.getEnvName().equals(server.getEnvName())
        			&&(server.isK8s() == buildParam.isK8s())){
        		newList.add(server);
        	}
        }
        Assert.notEmpty(newList, "appId："+buildParam.getAppId()+",envName："+buildParam.getEnvName()+"的服务器列表为空！");

        app.setServerList(newList);
        return app;
	}
	
	@Override
    public ResponseVo<Long> buildPre(@RequestBody BuildParam buildParam) {
		logger.debug("构建准备...{}",buildParam);
		
		Assert.hasText(buildParam.getBranchName(), "branchName不能为空");
        Assert.hasText(buildParam.getEnvName(), "envName不能为空");
        Assert.notNull(buildParam.getAppId(), "appId不能为空");
        Assert.notNull(buildParam.getBuildUserName(), "buildUserName不能为空");
        
        AppDetail app=this.valicateApp(buildParam);
        BuildRecord buildRecord=buildRecordService.insertBuildRecord(app, buildParam, EnumDefinition.BuildStatus.PASS.getCode());
		return ResponseVo.getSuccessResponse(buildRecord.getId());
    }
    
	/* (non-Javadoc)
	 * @see DeployService#build(BuildParam)
	 */
	@Override
	public ResponseVo<Long> build(@RequestBody BuildParam buildParam) {
		logger.debug("构建开始...{}",buildParam);
		
		AppDetail app=null;
		if(buildParam.getBuildId()==null){
			Assert.hasText(buildParam.getBranchName(), "branchName不能为空");
	        Assert.hasText(buildParam.getEnvName(), "envName不能为空");
	        Assert.notNull(buildParam.getAppId(), "appId不能为空");
	        Assert.notNull(buildParam.getBuildUserName(), "buildUserName不能为空");
	        
	      	app=this.valicateApp(buildParam);
		}else{
			BuildRecord buildRecord=buildRecordService.selectById(buildParam.getBuildId());
	        Assert.notNull(buildRecord, "没有查询到buildRecord");
		}
		
		this.valicateDonetSystem(buildParam);
		
        long buildId=buildRecordService.executeBuild(app, buildParam);
		return ResponseVo.getSuccessResponse(buildId);
	}
	
	/**
	 * 功能描述: <br>
	 * 如果dotnet类型的系统有正在进行中或者准备构建的状态，则直接返回失败
	 *
	 * @param buildParam
	 */
	private void valicateDonetSystem(BuildParam buildParam){
		BuildModel buildModelParam=new BuildModel();
        buildModelParam.setAppId(buildParam.getAppId());
		buildModelParam.setEnv(buildParam.getEnvName());
        BuildModel buildModel=buildModelService.selectOne(buildModelParam);
//        if(SystemTypeEnums.DOTNET.toString().equals(buildModel.getSystemType())){
//        	BuildRecord buildRecordParam=new BuildRecord();
//        	buildRecordParam.setAppId(buildModel.getAppId());
//        	buildRecordParam.setDelStatus(0);
//        	List<BuildRecord> buildRecordList=buildRecordService.selectPage(new Page<>(1, 5), buildRecordParam, " create_time desc").getRecords();
//        	boolean flag=true;
//        	for(BuildRecord buildRecord:buildRecordList){
//        		com.secsbrain.deploy.client.model.BuildRecord recordResult=parseBuildRecord(buildRecord);
//        		if(EnumDefinition.BuildStatus.ING.getCode().equals(recordResult.getStatus())
//        				|| EnumDefinition.BuildStatus.WAIT.getCode().equals(recordResult.getStatus())){
//        			flag=false;
//        			break;
//        		}
//        	}
//        	Assert.isTrue(flag, "已经有正在构建中或者准备构建的记录，请稍后再执行");
//        }
	}
	
	
	/* (non-Javadoc)
	 * @see DeployService#buildBatch(BuildParam[])
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ResponseVo<BatchBuildResult> buildBatch(@RequestBody BatchBuildParam batchBuildParam) {
		logger.debug("批量构建开始...{}",JSON.toJSONString(batchBuildParam));
        Assert.notNull(batchBuildParam.getBatchId(), "batchId不能为空");
		Assert.notEmpty(batchBuildParam.getBuildParams(),"构建参数不能为空");

		BatchBuildResult batchBuildResult=new BatchBuildResult();
		int successCount=0;
		Map<Long, String> failMap=new HashMap<Long, String>();
		for(BuildParam buildParam:batchBuildParam.getBuildParams()){
			try {
				AppDetail app=this.valicateApp(buildParam);
				buildParam.setBatchId(batchBuildParam.getBatchId());
				buildRecordService.executeBuild(app, buildParam);
				successCount++;
			} catch (Exception e) {
				logger.error("构建失败！",e);
				failMap.put(buildParam.getAppId(), e.getMessage());
			}
		}
		batchBuildResult.setFailAppMsg(failMap);
		batchBuildResult.setSuccessCount(successCount);
		batchBuildResult.setTotalCount(batchBuildParam.getBuildParams().length);
		
		if(successCount==0){
			return ErrorCodeEnum.ERROR_COMMON_HANDING.getResponseVo(failMap.get(batchBuildParam.getBuildParams()[0].getAppId()));
		}
		return ResponseVo.getSuccessResponse(batchBuildResult);
	}
	
	/* (non-Javadoc)
	 * @see DeployService#buildByJobName(JobNameBuildParam)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ResponseVo<?> buildByJobName(@RequestBody JobNameBuildParam jobNameBuildParam) {
        Assert.hasText(jobNameBuildParam.getJobName(), "jobName不能为空");

		Map<String, String> map=new HashMap<String, String>();
		if(StringUtils.isNotEmpty(jobNameBuildParam.getJsonParams())){
			map=JSON.parseObject(jobNameBuildParam.getJsonParams(), Map.class);
		}
		
		JenkinsHttpUtils jenkinsHttpUtils=new JenkinsHttpUtils(jenkinsUrl, userid, token);
		HttpResponse httpResponse=jenkinsHttpUtils.submitPost(jenkinsUrl+"/job/"+jobNameBuildParam.getJobName()+"/buildWithParameters", map);
		String result=httpResponse.getResult();
		if(result!=null){
			logger.error(result);
			//如果jenkins有返回，说明执行失败了
			return ErrorCodeEnum.ERROR_COMMON_SYSTEM.getResponseVo(result);
		}
		return ResponseVo.getSuccessResponse();
	}

	/* (non-Javadoc)
	 * @see DeployService#getBuildLog(java.lang.Long, java.lang.Long)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ResponseVo<BuildLog> getBuildLog(Long buildId, Long start,String env) {
        Assert.notNull(buildId, "buildId不能为空");
		BuildRecord buildRecord=buildRecordService.selectById(buildId);
        Assert.notNull(buildRecord, "没有查询到buildRecord");
        if(EnumDefinition.BuildStatus.PASS.getCode().equals(buildRecord.getStatus())
        		|| EnumDefinition.BuildStatus.WAIT.getCode().equals(buildRecord.getStatus())){
    		return ErrorCodeEnum.ERROR_COMMON_CHECK.getResponseVo("该构建暂未产生日志");
        }
        
        if(start==null){
        	start=0L;
        }
        
        Map<String, String> params=new HashMap<String, String>();
        params.put("start", start+"");
        
    	JenkinsHttpUtils jenkinsHttpUtils=null;
		if(Server.K8S_HOSTNAME.equals(buildRecord.getHostNames())){
			jenkinsHttpUtils=new JenkinsHttpUtils(jenkinsK8sUrl, useridK8s, tokenK8s);	  	
		}else{
			jenkinsHttpUtils=new JenkinsHttpUtils(jenkinsUrl, userid, token);	  	
		}
        HttpResponse httpResponse = jenkinsHttpUtils.submitPost("/job/"+buildRecord.getAppName()
        	+"/"+buildRecord.getBuildNo()+"/logText/progressiveText", params);
        
        BuildLog buildLog=new BuildLog();
        buildLog.setLogContent(httpResponse.getResult());
        buildLog.setxMoreData(httpResponse.getxMoreData());
        buildLog.setxTextSize(httpResponse.getxTextSize());
		return ResponseVo.getSuccessResponse(buildLog);
	}
    
	/* (non-Javadoc)
	 * @see DeployService#queryBuildListByAppId(java.lang.Long, java.lang.Integer, java.lang.Integer)
	 */
	@Override
	public ResponseVo<List<com.secsbrain.deploy.client.model.BuildRecord>> queryBuildListByAppId(Long appId, String envName, Integer page,
                                                                                                 Integer limit) {
        Assert.notNull(appId, "appId不能为空");
        if(page==null){
        	page=1;
        }
        if(limit==null){
        	limit=10;
        }
		
		BuildRecord buildRecordParam=new BuildRecord();
		buildRecordParam.setAppId(appId);
		buildRecordParam.setDelStatus(0);
		buildRecordParam.setEnv(envName);
    	Page<BuildRecord> pageBean=new Page<BuildRecord>(page, limit);
    	Page<BuildRecord> pageResult=buildRecordService.selectPage(pageBean, buildRecordParam, "create_time desc");
    	List<com.secsbrain.deploy.client.model.BuildRecord> resultList=new ArrayList<>();
    	for(BuildRecord buildRecord:pageResult.getRecords()){
    		resultList.add(parseBuildRecord(buildRecord));
    	}
		return ResponseVo.getSuccessResponse(pageResult.getTotal(), resultList);
	}
	
	/* (non-Javadoc)
	 * @see DeployService#queryBuildList(java.lang.Integer, java.lang.Integer, BuildQuery)
	 */
	@Override
	public ResponseVo<List<com.secsbrain.deploy.client.model.BuildRecord>> queryAllBuildList(Integer page, Integer limit,
                                                                                             String sortBy, String descending, String appName, String envName, String branchName, String startDate, String endDate, Integer status, String createName) {
		if(page==null){
        	page=1;
        }
        if(limit==null){
        	limit=10;
        }
		
		BuildRecord buildRecordParam=new BuildRecord();
		if(StringUtils.isNotEmpty(appName)){
			buildRecordParam.setAppName(appName);
		}
		if(StringUtils.isNotEmpty(branchName)){
			buildRecordParam.setBranch(branchName);
		}
		if(StringUtils.isNotEmpty(createName)){
			buildRecordParam.setCreateName(createName);
		}
		if(StringUtils.isNotEmpty(envName)){
			buildRecordParam.setEnv(envName);
		}
		if(status!=null){
			buildRecordParam.setStatus(status);
		}
		if(StringUtils.isNotEmpty(startDate)&&StringUtils.isNotEmpty(endDate)
				&&!"null".equals(startDate)&&!"null".equals(endDate)){
			buildRecordParam.setStartTime(startDate+" 00:00:00");
			buildRecordParam.setEndTime(endDate+" 23:59:59");
		}
		
    	Page<BuildRecord> pageBean=new Page<BuildRecord>(page, limit);
    	String orderCondition=sortBy+" "+(Boolean.parseBoolean(descending)?"desc":"asc");
    	if(StringUtils.isEmpty(sortBy)||"null".equals(sortBy)){
    		orderCondition="create_time desc";
    	}
    	Page<BuildRecord> pageResult=buildRecordService.queryBuildRecordPageList(pageBean, buildRecordParam, orderCondition);
    	List<com.secsbrain.deploy.client.model.BuildRecord> resultList=new ArrayList<>();
    	for(BuildRecord buildRecord:pageResult.getRecords()){
    		resultList.add(parseBuildRecord(buildRecord));
    	}
		return ResponseVo.getSuccessResponse(pageResult.getTotal(), resultList);
	}
	
	/* (non-Javadoc)
	 * @see DeployService#queryBuildListByBatchId(java.lang.Long)
	 */
	@Override
	public ResponseVo<List<com.secsbrain.deploy.client.model.BuildRecord>> queryBuildListByBatchId(Long batchId,String env) {
        Assert.notNull(batchId, "batchId不能为空");
        BuildRecord buildRecordParam=new BuildRecord();
		buildRecordParam.setBatchId(batchId);
		buildRecordParam.setDelStatus(0);
		List<BuildRecord> buildRecordList=buildRecordService.selectList(buildRecordParam);
		List<com.secsbrain.deploy.client.model.BuildRecord> resultList=new ArrayList<>();
    	for(BuildRecord buildRecord:buildRecordList){
    		resultList.add(parseBuildRecord(buildRecord));
    	}
    	return ResponseVo.getSuccessResponse(resultList);
	}
	
	/* (non-Javadoc)
	 * @see DeployService#queryBuildListByGroupId(java.lang.Long)
	 */
	@Override
	public ResponseVo<List<com.secsbrain.deploy.client.model.BuildRecord>> queryBuildListByGroupId(Long groupId, String envName) {
        Assert.notNull(groupId, "groupId不能为空");

		BuildRecord buildRecordParam=new BuildRecord();
		buildRecordParam.setGroupId(groupId);
		buildRecordParam.setDelStatus(0);
		buildRecordParam.setEnv(envName);
		List<BuildRecord> buildRecordList=buildRecordService.selectList(buildRecordParam, "create_time desc");
    	List<com.secsbrain.deploy.client.model.BuildRecord> resultList=new ArrayList<>();
    	for(BuildRecord buildRecord:buildRecordList){
    		resultList.add(parseBuildRecord(buildRecord));
    	}
		return ResponseVo.getSuccessResponse(resultList);
	}
	
	@SuppressWarnings("rawtypes")
	private com.secsbrain.deploy.client.model.BuildRecord parseBuildRecord(BuildRecord buildRecord){
		com.secsbrain.deploy.client.model.BuildRecord result=new com.secsbrain.deploy.client.model.BuildRecord();
		result.setAppId(buildRecord.getAppId());
		result.setAppName(buildRecord.getAppName());
		result.setBranch(buildRecord.getBranch());
		result.setBuildId(buildRecord.getId());
		result.setBuildNo(buildRecord.getBuildNo());
		result.setCreateTime(buildRecord.getCreateTime());
		result.setCreateUser(buildRecord.getCreateName());
		result.setEnv(buildRecord.getEnv());
		result.setHostNames(buildRecord.getHostNames());
		result.setPackageCmd(buildRecord.getPackageCmd());
		result.setDeployCmd(buildRecord.getDeployCmd());
		result.setTestCmd(buildRecord.getTestCmd());
		result.setGroupId(buildRecord.getGroupId());
		result.setGrayPercent(buildRecord.getGrayPercent());
		result.setGroupName(buildRecord.getGroupName());
		result.setApprovalId(buildRecord.getApprovalId());
		
		if(EnumDefinition.BuildStatus.ING.getCode().equals(buildRecord.getStatus())){
			Map<String, String> params=new HashMap<>();
			params.put("tree", "result,building");
	    	JenkinsHttpUtils jenkinsHttpUtils=null;
			if(Server.K8S_HOSTNAME.equals(buildRecord.getHostNames())){
				jenkinsHttpUtils=new JenkinsHttpUtils(jenkinsK8sUrl, useridK8s, tokenK8s);	  	
			}else{
				jenkinsHttpUtils=new JenkinsHttpUtils(jenkinsUrl, userid, token);	  	
			}
			HttpResponse httpResponse = jenkinsHttpUtils.submitPost("/job/"+buildRecord.getAppName()
        		+"/"+buildRecord.getBuildNo()+"/api/json", params);
			try{
				Map map=JSON.parseObject(httpResponse.getResult(),Map.class);
				boolean building=(Boolean)map.get("building");
				String status=(String)map.get("result");
				if(building){
					result.setStatus(buildRecord.getStatus());
				}else{
					result.setStatus("SUCCESS".equals(status)? EnumDefinition.BuildStatus.SUCCESS.getCode(): EnumDefinition.BuildStatus.FAILUE.getCode());
					//更新数据库状态
					BuildRecord buildRecordUp=new BuildRecord();
					buildRecordUp.setId(buildRecord.getId());
					buildRecordUp.setStatus(result.getStatus());
					buildRecordService.updateSelectiveById(buildRecordUp);
				}
			}catch (Exception e){
				logger.error("",e);
				logger.debug("发生错误的应用：{},构建号：{}",buildRecord.getAppName(),buildRecord.getBuildNo());
				result.setStatus(EnumDefinition.BuildStatus.FAILUE.getCode());
			}

		}else{
    		result.setStatus(buildRecord.getStatus());
		}
		return result;
	}
	
	
	/* (non-Javadoc)
	 * @see DeployService#queryBuildRecordByBuildId(java.lang.Long)
	 */
	@Override
	public ResponseVo<com.secsbrain.deploy.client.model.BuildRecord> queryBuildRecordByBuildId(Long buildId,String env) {
        Assert.notNull(buildId, "buildId不能为空");
        BuildRecord buildRecord=buildRecordService.selectById(buildId);
        Assert.notNull(buildRecord, "没有查询到相应的构建记录");
		return ResponseVo.getSuccessResponse(this.parseBuildRecord(buildRecord));
	}
	
	/* (non-Javadoc)
	 * @see DeployService#percentRelease(java.lang.Long, java.lang.Integer)
	 */
	@Override
	public ResponseVo<Integer> percentRelease(Long groupId, Integer percent) {
		logger.debug("灰度切流...groupId:{},percent:{}",groupId,percent);
		
		Assert.notNull(groupId, "groupId不能为空");
        Assert.notNull(percent, "percent不能为空");
        return ResponseVo.getSuccessResponse(buildRecordService.handleGrayRelease(percent, groupId));
	}
	
	/**
     * 功能描述: <br>
     * 更新build为发布中
     *
     * @param buildRecord
     * @return
     */
    @RequestMapping(value = "/jenkins/building", method = RequestMethod.PUT)
    public ResponseVo<?> building(@RequestBody BuildRecord buildRecord) {
    	logger.debug("=====jenkins building=====");
    	
        Assert.notNull(buildRecord.getId(), "buildId不能为空");
        Assert.notNull(buildRecord.getBuildNo(), "buildNo不能为空");
    	
    	BuildRecord buildRecordUp=new BuildRecord();
    	buildRecordUp.setId(buildRecord.getId());
    	buildRecordUp.setBuildNo(buildRecord.getBuildNo());
    	buildRecordUp.setStatus(EnumDefinition.BuildStatus.ING.getCode());
		buildRecordService.updateSelectiveById(buildRecordUp);
		
    	return ResponseVo.getSuccessResponse();
    }

	/* (non-Javadoc)
	 * @see DeployService#healthCheck(HealthDto)
	 */
	@Override
	public ResponseVo<?> healthCheck(@RequestBody HealthDto healthDto) {
		try {
			boolean flag=buildRecordService.healthCheck(healthDto);
			if(!flag){
				return ErrorCodeEnum.ERROR_COMMON_PARAM.getResponseVo("健康检查不通过");
			}
		} catch (Exception e) {
			return ErrorCodeEnum.ERROR_COMMON_PARAM.getResponseVo(e.getMessage());
		}
		return ResponseVo.getSuccessResponse();
	}

	/* (non-Javadoc)
	 * @see DeployService#serverUp(java.lang.Long, java.lang.String)
	 */
	@Override
	public ResponseVo<?> serverUp(Long appId, String host) {
		try {
			boolean flag=buildRecordService.serverUp(appId, host);
			if(!flag){
				return ErrorCodeEnum.ERROR_COMMON_PARAM.getResponseVo("上线服务失败");
			}
		} catch (Exception e) {
			return ErrorCodeEnum.ERROR_COMMON_PARAM.getResponseVo(e.getMessage());
		}
		return ResponseVo.getSuccessResponse();
	}

}
